package com.hxzy.framework.web.security.service;

import com.hxzy.common.constant.Constants;
import com.hxzy.common.core.domain.entity.User;
import com.hxzy.common.core.domain.model.LoginUser;
import com.hxzy.common.exception.ServiceException;
import com.hxzy.common.exception.user.CaptchaExpireException;
import com.hxzy.common.exception.user.UserPasswordNotMatchException;
import com.hxzy.common.security.TokenService;
import com.hxzy.common.utils.DateUtils;
import com.hxzy.common.utils.MessageUtils;
import com.hxzy.common.utils.ServletUtils;
import com.hxzy.common.utils.StringUtils;
import com.hxzy.common.utils.ip.IpUtils;
import com.hxzy.common.utils.text.Convert;
import com.hxzy.framework.manager.AsyncManager;
import com.hxzy.framework.manager.factory.AsyncFactory;
import com.hxzy.system.dto.LoginUserDTO;
import com.hxzy.system.service.SysConfigService;
import com.hxzy.system.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

/**
 * 登录校验证类说明
 *
 * @author admin
 * @date 2021-09-25
 */
@Component
public class LoginService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * spring security安全管理框架
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    /**
     * jwt+redis生成登录令牌
     */
    @Autowired
    private TokenService tokenService;

    @Autowired
    private SysConfigService sysConfigService;

    @Autowired
    private UserService userService;


    /**
     * 登录如果成功返回加密后的令牌
     * @param loginUserDTO
     * @return  jwt加密
     */
    public String login(LoginUserDTO loginUserDTO) {

        String value=this.sysConfigService.selectValueByKey("sys.account.captchaOnOff");
        boolean captchaValue= Convert.toBool(value);
        //判断是判断验证码
        if(captchaValue){
            captchaValidate(loginUserDTO.getUsername(), loginUserDTO.getCode(),loginUserDTO.getUuid());
        }

        /*
         //加上shiro框架
        UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(adminLoginDTO.getUsername(), adminLoginDTO.getPassword());
        //创建一个登录Subject
        Subject  subject= SecurityUtils.getSubject();
        //3、登录，自动调用你写的 realm类  AuthorizingRealm类
        try {
            subject.login(usernamePasswordToken);
            }
         */

        //spring security做认证
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken=new UsernamePasswordAuthenticationToken(loginUserDTO.getUsername(),loginUserDTO.getPassword());
        //登录对象  该方法会去调用UserDetailsServiceImpl.loadUserByUsername  接口UserDetailsService
        Authentication authentication = null;

        try{
            authentication= this.authenticationManager.authenticate(usernamePasswordAuthenticationToken);
        }catch(Exception e){
            //密码错误
            if (e instanceof BadCredentialsException)
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginUserDTO.getUsername(), Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            }
            else
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginUserDTO.getUsername(), Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        }

        //登录成功写入到数据库
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginUserDTO.getUsername(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));

        //取得登录后的自定义对象
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();

        //更新最后的登录时间和IP
        recordLoginInfo(loginUser.getUserId());

        //把这个对象转成 加密的 字符串

        return this.tokenService.createToken(loginUser);
    }


    /**
     * 记录登录信息
     *
     * @param userId 用户ID
     */
    public void recordLoginInfo(Long userId)
    {
        User sysUser = new User();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
        sysUser.setLoginDate(DateUtils.getNowDate());
        this.userService.updateByPrimaryKeySelective(sysUser);
    }
    /**
     * 判断验证码是否正确
     * @param code
     * @param uuid
     */
    private void captchaValidate(String username,String code, String uuid) {
        String redisKey= Constants.CAPTCHA_CODE_KEY+uuid;
        String redisValue=this.stringRedisTemplate.opsForValue().get(redisKey);
        //验证码过期了
        if(StringUtils.isBlank(redisValue)){
            //异步记录日志
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
            throw new CaptchaExpireException();
        }

        if(!code.equalsIgnoreCase(redisValue)){
            //异步记录日志
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
            throw new CaptchaExpireException();
        }
    }

}
